package lan.battletank.environment;

import lan.battletank.R;
import lan.battletank.element.BarricadeEntity;
import lan.battletank.element.BaseBattleUnitElement;
import lan.battletank.element.BaseElement;
import lan.battletank.element.TankEntity;
import lan.battletank.logic.ElementStatusLogic;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.util.Log;

public class Stage {

    public static boolean isFloorHit;

    private Context mContext;
    private Bitmap mBarricadeImage; // barricade image to use
    private BarricadeEntity mFloor[][]; // array that contains the stage barricade objects
    private int n;  // the base layer barricade number
    private int mCheckRangeY;   // if bullet is outside this range then do not need collision check
    private int mHorizontalLine;

    /** used for collision check and tank move check */
    private int mX;
    private int mY;
    private float mBoundToCenterX;
    private float mBoundToBottomY;

    public Stage(Context context, int canvasWidth, int canvasHeight) {
        mContext = context;
        Resources res = mContext.getResources();
        // Faster to draw in bitmap.
        mBarricadeImage = Bitmap.createScaledBitmap(BitmapFactory.decodeResource(res, R.drawable.barricade), EnvConst.BARRICADE_WIDTH, EnvConst.BARRICADE_HEIGHT, true);
        mCheckRangeY = canvasHeight - (EnvConst.LAND_HEIGHT + EnvConst.STAGE_HEIGHT * EnvConst.BARRICADE_HEIGHT);
        n = canvasWidth / EnvConst.BARRICADE_WIDTH + 1; // add one more to ensure the screen is filled up
        mBoundToCenterX = TankEntity.TANK_WIDTH / (2 * EnvConst.BARRICADE_WIDTH);
        mBoundToBottomY = TankEntity.TANK_HEIGHT / EnvConst.BARRICADE_HEIGHT;
        mHorizontalLine = canvasHeight - EnvConst.LAND_HEIGHT;
        initStage();
        
    }

    public void initStage() {
    	mFloor = new BarricadeEntity[EnvConst.STAGE_HEIGHT][n];
        isFloorHit = false;
        int centerX = 0;
        int centerY = 0;
        int baseY = mHorizontalLine - EnvConst.BARRICADE_HEIGHT / 2;
        for (int i = 0; i < EnvConst.STAGE_HEIGHT; i++) {
            centerY = baseY - (i * EnvConst.BARRICADE_WIDTH);
            for (int j = 0; j < n; j++) {
                centerX = j * EnvConst.BARRICADE_WIDTH + EnvConst.BARRICADE_WIDTH / 2;
                mFloor[i][j] = new BarricadeEntity();
                mFloor[i][j].setPosition(centerX, centerY);
            }
        }
        // for test
        mFloor[3][1].destroy();
		mFloor[3][2].destroy();
		mFloor[3][3].destroy();
        mFloor[3][4].destroy();
		mFloor[3][5].destroy();
		mFloor[2][1].destroy();
		mFloor[2][2].destroy();
		mFloor[2][3].destroy();
		
		mFloor[3][n - 2].destroy();
		mFloor[3][n - 3].destroy();
        mFloor[3][n - 4].destroy();
		mFloor[3][n - 5].destroy();
		mFloor[3][n - 6].destroy();
	}

	public void draw(Canvas c) {
        for (int i = 0; i < EnvConst.STAGE_HEIGHT; i++) {
            for (int j = 0; j < n; j++) {
                if (mFloor[i][j].isAlive()) {
                    mFloor[i][j].draw(mBarricadeImage, c);
                }
            }
        }
    }

    public int getPlayerInitialCenterY(BaseBattleUnitElement tank) {
        for (int i = EnvConst.STAGE_HEIGHT - 1; i > -1; i--) {
            for (int j = 0; j < n; j++) {
                if (mFloor[i][j].isAlive()) {
                    if (tank.centerX >= mFloor[i][j].bound_l && tank.centerX <= mFloor[i][j].bound_r) {
                        return (int) mFloor[i][j].bound_t - tank.halfHeight;
                    }
                }
            }
        }
        return 0;
    }

    public int getEnemyInitialCenterY(BaseBattleUnitElement target) {
        // for (int i = EnvConst.STAGE_HEIGHT - 1; i > -1; i --) {
        // for (int j = n - 1; j > -1; j --) {
        // if (mFloor[i][j].isAlive()) {
        // if (target.centerX >= mFloor[i][j].bound_l && target.centerX <= mFloor[i][j].bound_r) {
        // return (int)mFloor[i][j].bound_t - target.halfHeight;
        // }
        // }
        // }
        // }
        mX = (int) (target.centerX / EnvConst.BARRICADE_WIDTH);
        for (int y = EnvConst.STAGE_HEIGHT - 1; y > -1; y--) {
            if (mFloor[y][mX].isAlive()) {
                return (int) mFloor[y][mX].bound_t - target.halfHeight;
            }
        }
        return 0;
    }

    public boolean bulletCollide(BaseElement bullet) {
        // get the closest barricade to avoid abundent calculation
        if (mCheckRangeY - bullet.halfHeight < bullet.centerY) {
            mX = (int) (bullet.centerX / EnvConst.BARRICADE_WIDTH);
            mY = (int) ((mHorizontalLine - bullet.centerY - bullet.halfHeight) / EnvConst.BARRICADE_HEIGHT);

            try {
                if (mFloor[mY][mX].isAlive()) {
                    if (ElementStatusLogic.isColliding(bullet, mFloor[mY][mX])) {
                        isFloorHit = true;
                        mFloor[mY][mX].destroy();
                        return true;
                    }
                }
            } catch (ArrayIndexOutOfBoundsException e) {
                Log.v("FLOORCHECK", mX + "," + mY);
                throw e;
            }
        }
        return false;
    }

    public void tankFallCheck(BaseBattleUnitElement tank) {
        float temp = tank.centerX / EnvConst.BARRICADE_WIDTH;
        boolean specialCheck = false;
        if ((int) (tank.centerX % EnvConst.BARRICADE_WIDTH) == 0) {
            // tank's centerX is just on the edge of the barricade
            specialCheck = true;
        }
        mX = (int) temp;
        mY = (int) ((mHorizontalLine - tank.centerY - tank.halfHeight - 1) / EnvConst.BARRICADE_HEIGHT);
        if (mY < 0) {
            // tank is destroyed
            tank.isFalling = false;
            tank.isAlive = false;
            return;
        }
        tank.leftStable = false;
        tank.rightStable = false;
        if (!specialCheck && !mFloor[mY][mX].isAlive()) {
            int mXR = (int) (temp + mBoundToCenterX);
            int mXL = (int) (temp - mBoundToCenterX);
            for (int i = mXL; i <= mXR; i++) {
                if (mFloor[mY][i].isAlive()) {
                    if (i < mX) {
                        tank.leftStable = true;
                    } else if (i > mX) {
                        tank.rightStable = true;
                    }
                }
            }
            if (tank.leftStable && tank.rightStable) {
                tank.isFalling = false;
            } else if (tank.leftStable) {
                tank.isFalling = true;
                tank.isFallingR = true;
            } else if (tank.rightStable) {
                tank.isFalling = true;
                tank.isFallingL = true;
            }
        } else if (specialCheck && (!mFloor[mY][mX].isAlive() && !mFloor[mY][mX - 1].isAlive())) {
            // falling vertically
            tank.isFalling = true;
            tank.isFallingL = false;
            tank.isFallingR = false;
        } else {
            tank.leftStable = true;
            tank.rightStable = true;
            tank.isFalling = false;
            tank.isFallingL = false;
            tank.isFallingR = false;
        }
    }

    public boolean canGoLeft(BaseBattleUnitElement tank) {
        mY = (int) ((mHorizontalLine - tank.centerY - tank.halfHeight - 1) / EnvConst.BARRICADE_HEIGHT);
        if (mY == EnvConst.STAGE_HEIGHT - 1) {
            // on the highest ground
            return true;
        } else {
            int upperY = (int) (mY + 1 + mBoundToBottomY);
            if (upperY > EnvConst.STAGE_HEIGHT - 1) {
                upperY = EnvConst.STAGE_HEIGHT - 1;
            }
            int mXL = (int) (tank.centerX / EnvConst.BARRICADE_WIDTH - mBoundToCenterX);
            for (int i = mY + 1; i <= upperY; i++) {
                if (mFloor[i][mXL].isAlive() && tank.centerX - tank.halfWidth < mFloor[i][mXL].bound_r) {
                    return false;
                }
                if (mXL > 0) {
                    if (mFloor[i][mXL - 1].isAlive() && tank.centerX - tank.halfWidth < mFloor[i][mXL - 1].bound_r) {
                        return false;
                    }
                }
            }
        }
        return true;
    }

    public boolean canGoRight(BaseBattleUnitElement tank) {
        mY = (int) ((mHorizontalLine - tank.centerY - tank.halfHeight - 1) / EnvConst.BARRICADE_HEIGHT);
        if (mY == EnvConst.STAGE_HEIGHT - 1) {
            // on the highest ground
            return true;
        } else {
            int upperY = (int) (mY + 1 + mBoundToBottomY);
            if (upperY > EnvConst.STAGE_HEIGHT - 1) {
                upperY = EnvConst.STAGE_HEIGHT - 1;
            }
            int mXR = (int) (tank.centerX / EnvConst.BARRICADE_WIDTH + mBoundToCenterX);
            for (int i = mY + 1; i <= upperY; i++) {
                if (mFloor[i][mXR].isAlive() && tank.centerX + tank.halfWidth > mFloor[i][mXR].bound_l) {
                    return false;
                }
                if (mXR + 1 < n) {
                    if (mFloor[i][mXR + 1].isAlive() && tank.centerX + tank.halfWidth > mFloor[i][mXR + 1].bound_l) {
                        return false;
                    }
                }
            }
        }
        return true;
    }
}